import com.google.gson.Gson;
import org.apache.calcite.adapter.jdbc.JdbcSchema;
import org.apache.calcite.plan.RelOptUtil;
import org.apache.calcite.plan.RelTraitDef;
import org.apache.calcite.rel.RelNode;
import org.apache.calcite.rel.core.JoinRelType;
import org.apache.calcite.schema.Schema;
import org.apache.calcite.schema.SchemaPlus;
import org.apache.calcite.sql.fun.SqlStdOperatorTable;
import org.apache.calcite.sql.parser.SqlParser;
import org.apache.calcite.tools.FrameworkConfig;
import org.apache.calcite.tools.Frameworks;
import org.apache.calcite.tools.Programs;
import org.apache.calcite.tools.RelBuilder;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.stream.Collectors;

public class TestAlgebra {
    public static void main(String[] args) throws SQLException, IOException {
        SchemaPlus rootSchema = Frameworks.createRootSchema(true);

        String filepath = "D:\\studyWorkspace\\springboot-demo\\calcite-demo\\src\\main\\resources\\singleSource.json";
        Properties config = new Properties();
        config.put("model",filepath);
        config.put("lex", "MYSQL");
        Connection con = DriverManager.getConnection("jdbc:calcite:", config);

        String modelJsonStr = Files.readAllLines(Paths.get(filepath)).stream().collect(Collectors.joining("\n"));
        HashMap map = new Gson().fromJson(modelJsonStr, HashMap.class);
        List<Map> schemas = (List<Map>) map.get("schemas");

        Schema mysql = JdbcSchema.create(rootSchema, "mysql" , (Map<String,Object>)schemas.get(0).get("operand"));
        // rootSchema.add("gbasedbt",gbasedbt);
        rootSchema.add("mysql",mysql);

        SqlParser.Config insensitiveParser = SqlParser.configBuilder()
                .setCaseSensitive(false)
                .build();

        FrameworkConfig frameworkConfig = Frameworks.newConfigBuilder()
                .parserConfig(insensitiveParser)
                .defaultSchema(rootSchema)
                .build();


        /*FrameworkConfig frameworkConfig2 =  Frameworks.newConfigBuilder()
                .parserConfig(SqlParser.Config.DEFAULT)
                .defaultSchema(rootSchema)
                .traitDefs((List<RelTraitDef>) null)
                .programs(Programs.heuristicJoinOrder(Programs.RULE_SET, true, 2));*/

        //TableScan
        final RelBuilder builder = RelBuilder.create(frameworkConfig);
        final RelNode node = builder
                .scan("EMP")
                .build();
        System.out.println(RelOptUtil.toString(node));


        //Adding a Project
        final RelNode node2 = builder
                .scan("EMP")
                .project(builder.field("DEPTNO"), builder.field("ENAME"))
                .build();
        System.out.println(RelOptUtil.toString(node));

        /**
         * SELECT deptno, count(*) AS c, sum(sal) AS s
         * FROM emp
         * GROUP BY deptno
         * HAVING count(*) > 10
         */
        //Adding a Filter and AggregatePermalink
        final RelNode node3 = builder
                .scan("EMP")
                .aggregate(builder.groupKey("DEPTNO"),
                        builder.count(false, "C"),
                        builder.sum(false, "S", builder.field("SAL")))
                .filter(
                        builder.call(SqlStdOperatorTable.GREATER_THAN,
                                builder.field("C"),
                                builder.literal(10)))
                .build();
        System.out.println(RelOptUtil.toString(node));


        /**
         *                 join
         *              /      \
         *         join          join
         *       /      \      /      \
         * CUSTOMERS ORDERS LINE_ITEMS PRODUCTS
         */
        final RelNode left = builder
                .scan("CUSTOMERS")
                .scan("ORDERS")
                .join(JoinRelType.INNER, "ORDER_ID")
                .build();

        final RelNode right = builder
                .scan("LINE_ITEMS")
                .scan("PRODUCTS")
                .join(JoinRelType.INNER, "PRODUCT_ID")
                .build();

        final RelNode result = builder
                .push(left)
                .push(right)
                .join(JoinRelType.INNER, "ORDER_ID")
                .build();

      /*  final RelNode result = builder
                .push(input)
                .adoptConvention(EnumerableConvention.INSTANCE)
                .sort(toCollation)
                .build();*/
    }
}
